﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace WholeSlideImageLibrary.Core
{
    public sealed class PhysicalDirectorySource : DirectorySourceInfo
    {
        private readonly DirectoryInfo _directoryInfo;

        public override string? DirectoryName => _directoryInfo.Name;

        public PhysicalDirectorySource(string directoryName)
        {
            if (directoryName is null)
            {
                throw new ArgumentNullException(nameof(directoryName));
            }

            var info = new DirectoryInfo(directoryName);
            if (!info.Exists)
            {
                throw new DirectoryNotFoundException();
            }

            _directoryInfo = info;
        }

        public PhysicalDirectorySource(DirectoryInfo directoryInfo)
        {
            if (directoryInfo is null)
            {
                throw new ArgumentNullException(nameof(directoryInfo));
            }

            if (!directoryInfo.Exists)
            {
                throw new DirectoryNotFoundException();
            }

            _directoryInfo = directoryInfo;
        }

        public override bool CheckDirectoryExists(string directoryName)
        {
#if NO_PATH_JOIN
            string path = Path.Combine(_directoryInfo.FullName, directoryName);
#else
            string path = Path.Join(_directoryInfo.FullName, directoryName);
#endif
            return Directory.Exists(path);
        }

        public override bool CheckFileExists(string fileName)
        {
#if NO_PATH_JOIN
            string path = Path.Combine(_directoryInfo.FullName, fileName);
#else
            string path = Path.Join(_directoryInfo.FullName, fileName);
#endif
            return File.Exists(path);
        }

        public override ValueTask<DirectorySourceInfo?> GetDirectoryAsync(string directoryName, CancellationToken cancellationToken = default)
        {
#if NO_PATH_JOIN
            string path = Path.Combine(_directoryInfo.FullName, directoryName);
#else
            string path = Path.Join(_directoryInfo.FullName, directoryName);
#endif
            var directoryInfo = new DirectoryInfo(path);
            if (!directoryInfo.Exists)
            {
                return default;
            }
            return new ValueTask<DirectorySourceInfo?>(new PhysicalDirectorySource(directoryInfo));
        }

        public override ValueTask<FileSourceInfo?> GetFileAsync(string fileName, CancellationToken cancellationToken = default)
        {
#if NO_PATH_JOIN
            string path = Path.Combine(_directoryInfo.FullName, fileName);
#else
            string path = Path.Join(_directoryInfo.FullName, fileName);
#endif
            var fileInfo = new FileInfo(path);
            if (!fileInfo.Exists)
            {
                return default;
            }
            return new ValueTask<FileSourceInfo?>(new PhysicalFileSource(fileInfo));
        }

        public override ValueTask<FileSourceReader?> OpenFileAsync(string fileName, CancellationToken cancellationToken = default)
        {
#if NO_PATH_JOIN
            string path = Path.Combine(_directoryInfo.FullName, fileName);
#else
            string path = Path.Join(_directoryInfo.FullName, fileName);
#endif
            var fileInfo = new FileInfo(path);
            if (!fileInfo.Exists)
            {
                return default;
            }
            return new ValueTask<FileSourceReader?>(new PhysicalFileReader(fileInfo.FullName));
        }

        public override IEnumerable<string> ListDirectory()
        {
            return Directory.EnumerateDirectories(_directoryInfo.FullName);
        }

        public override IEnumerable<string> ListFiles()
        {
            return Directory.EnumerateFiles(_directoryInfo.FullName);
        }
    }
}
